﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Net;
using Microsoft.SharePoint.Client;
using SP = Microsoft.SharePoint.Client;
using System.IO;

namespace Sharepoint.Client.Wrapper
{
    public class SPInfo
    {
        #region Propertys

        const String FolderContentTypeId = "0x0120";
        const String ItemContentTypeId1 = "0x0100";
        const String ItemContentTypeId2 = "0x0101";

        private ClientContext _clientContext;
        public ClientContext clientContext
        {
            get
            {
                if (_clientContext == null)
                {

                    return _clientContext = new ClientContext(this.uri);
                }
                return _clientContext;
            }
        }

        private Uri uri { get; set; }
        // site collection
        private Site siteCollection
        {
            get
            { return this.clientContext.Site; }
        }
        // current web                                    
        private Web site
        {
            get
            { return this.clientContext.Web; }
        }

        #endregion

        #region Procedures

        // Default Credentials
        public SPInfo(String _uri)
        {
            this.uri = new Uri(_uri);
            _clientContext = new ClientContext(this.uri);
            _clientContext.Credentials = System.Net.CredentialCache.DefaultCredentials;
        }

        // Specify Credentials
        public SPInfo(String _uri, ICredentials _Credentials)
        {
            this.uri = new Uri(_uri);
            _clientContext = new ClientContext(this.uri);
            _clientContext.Credentials = _Credentials;
        }


        ~SPInfo()
        {
            this.clientContext.Dispose();
            _clientContext = null;
        }

        // Получаем главные списки и папки в них
        public ListStructs getLists()
        {
            ListStructs retlist = new ListStructs();

            try
            {

                this.clientContext.Load(this.site);
                this.clientContext.Load(this.site.Lists);
                this.clientContext.ExecuteQuery();
                // добавляем списки
                foreach (List list in this.site.Lists)
                {
                    ListStruct listStruct = new ListStruct(list.Title, this.uri);
                    listStruct.Guid = list.Id;
                    listStruct.IsLibrary = this.checkIsLibrary(list.ContentTypes);

                    // получаем относительный путь
                    this.clientContext.Load(list.RootFolder);
                    this.clientContext.ExecuteQuery();

                    listStruct.IsFolder = false;
                    listStruct.IsList = true;
                    listStruct.FileLeafRef = list.RootFolder.ServerRelativeUrl;
                    listStruct.FileRef = list.RootFolder.ServerRelativeUrl;
                    listStruct.FileDirRef = list.RootFolder.ServerRelativeUrl;
                    listStruct.ListDirRef = list.RootFolder.ServerRelativeUrl;
                    listStruct.Created = list.Created;
                    listStruct.ListId = list.Id;
                    // получаем папки
                    listStruct.childs = this.getFolderListItems(listStruct);

                    retlist.Add(listStruct);

                }
            }
            catch (Exception e)
            {
//                throw new ErrorEventArgs(e);
            }

            return retlist;
        }

        // получаем значения папок указанного списка
        public ListStructs getFolderListItems(ListStruct _listStruct)
        {
            ListStructs childStructs = new ListStructs();
            String _serverRelativeUrl = _listStruct.FileRef;
            List list = site.Lists.GetById(_listStruct.ListId);
            this.clientContext.Load(list);
            this.clientContext.ExecuteQuery();
            
            CamlQuery query = new CamlQuery();

            query.ViewXml = "<View Scope='RecursiveAll'>" +
                            "   <Query> " +
                            "   <Where> " +
                            "      <And>" +
                            "        <BeginsWith> " +
                            "           <FieldRef Name='ContentTypeId' />" +
                            "           <Value Type='ContentTypeId'>" + FolderContentTypeId + "</Value>" +
                            "        </BeginsWith> " +
                            "        <Eq> " +
                            "           <FieldRef Name='FileDirRef' />" +
                            "           <Value Type='Text'>" + _serverRelativeUrl + "</Value>" +
                            "        </Eq> " +
                            "      </And>" +
                            "   </Where> " +
                            "   </Query> " +
                            "</View>";

            ListItemCollection listItemCollection = list.GetItems(query);

            this.clientContext.Load(listItemCollection);
            this.clientContext.ExecuteQuery();

            foreach (ListItem oListItem in listItemCollection)
            {
                if (oListItem.FileSystemObjectType != FileSystemObjectType.Folder)
                    continue;

                Dictionary<string, object> d = oListItem.FieldValues;

                if (d.ContainsKey("FileRef") &&
                        d.ContainsKey("FileDirRef") &&
                        d.ContainsKey("FileLeafRef") &&
                        d.ContainsKey("GUID") &&
                        d.ContainsKey("Created") &&
                        (object)d["GUID"] != null &&
                        (object)d["FileRef"] != null &&
                        (object)d["FileDirRef"] != null &&
                        (object)d["FileLeafRef"] != null &&
                        (object)d["Created"] != null)
                {
                    // получаем папку
                    Guid folderGuid = (Guid)d["GUID"];
                    Folder folder = oListItem.ParentList.ParentWeb.GetFolderByServerRelativeUrl(d["FileRef"].ToString());
                    this.clientContext.Load(folder);
                    this.clientContext.ExecuteQuery();

                    ListStruct folderStruct = new ListStruct(folder.Name, this.uri);
                    folderStruct.Guid = (Guid)d["GUID"];
                    folderStruct.FileDirRef = d["FileDirRef"].ToString();
                    folderStruct.FileRef = d["FileRef"].ToString();
                    folderStruct.FileLeafRef = d["FileLeafRef"].ToString();
                    folderStruct.ListDirRef = _listStruct.ListDirRef;

                    folderStruct.ListId = list.Id;
                    folderStruct.ItemId = (int)d["ID"];
                    folderStruct.Created = (DateTime)d["Created"];

                    folderStruct.IsLibrary = _listStruct.IsLibrary;
                    folderStruct.IsList = false;
                    folderStruct.IsFolder = true;

                    folderStruct.childs = this.getFolderListItems(folderStruct);

                    childStructs.Add(folderStruct);
                }

            }

            return childStructs;
        }

        // Получение всех элементов 
        public ListStructs getListItems(ListStruct _listStruct)
        {
            ListStructs retListStructs = new ListStructs();

            List list = site.Lists.GetById(_listStruct.ListId);

            CamlQuery query = new CamlQuery();

            query.ViewXml = "<View Scope='RecursiveAll'>" +
                             "   <Query> " +
                             "   <Where> " +
                             "      <And>" +
                             "       <Eq>" +
                             "       <FieldRef Name='FileDirRef'/>" +
                                        String.Format("<Value Type='Text'>{0}</Value>", _listStruct.FileRef) +
                             "       </Eq>" +
                             "      <Or>" +
                             "       <BeginsWith> " +
                             "           <FieldRef Name='ContentTypeId' />" +
                                        String.Format("<Value Type='ContentTypeId'>{0}</Value>", ItemContentTypeId1) +
                             "       </BeginsWith> " +
                             "       <BeginsWith> " +
                             "           <FieldRef Name='ContentTypeId' />" +
                                        String.Format("<Value Type='ContentTypeId'>{0}</Value>", ItemContentTypeId2) +
                             "       </BeginsWith> " +
                             "      </Or>" +
                             "      </And>" +
                             "   </Where> " +
                             "   </Query> " +
                             "</View>";


            ListItemCollection listItemCollection = list.GetItems(query);

            this.clientContext.Load(listItemCollection);
            this.clientContext.ExecuteQuery();

            foreach (ListItem oListItem in listItemCollection)
            {
                Dictionary<string, object> d = oListItem.FieldValues;

                ListStruct listStruct = new ListStruct();
                listStruct.Uri = this.uri;
// if library
                if (_listStruct.IsLibrary)
                {
                    listStruct.FileLeafRef = d["FileLeafRef"].ToString();
                    listStruct.FileDirRef = d["FileDirRef"].ToString();
                }
                else
                {
                    listStruct.FileLeafRef = d["ID"].ToString();
                    listStruct.FileDirRef = _listStruct.ListDirRef;
                }

                listStruct.ListDirRef = _listStruct.ListDirRef;
                listStruct.FileRef = d["FileRef"].ToString();
                listStruct.Guid = (Guid)d["GUID"];
                listStruct.ListId = _listStruct.ListId;
                listStruct.ItemId = (int)d["ID"];
                listStruct.IsLibrary = _listStruct.IsLibrary;

                listStruct.Created = (DateTime)d["Created"];

                String titlestr = "No Title";
                if (d.ContainsKey("Title") && (object)d["Title"] != null)
                {
                    titlestr = d["Title"].ToString();
                }
                listStruct.Name = titlestr;

                retListStructs.Add(listStruct);
            }

            return retListStructs;
        }

        // Загрузка файла в указанную папку
        public static Boolean uploadFile(String _uri, String _fileToUpload, ListStruct _destination)
        {
            if (!System.IO.File.Exists(_fileToUpload))
                throw new FileNotFoundException("File not found.", _fileToUpload);

            if (!_destination.IsLibrary)
                throw new ArgumentException("List is not library");
// set file info 
            FileCreationInformation newFile = new FileCreationInformation();
            newFile.Content = System.IO.File.ReadAllBytes(_fileToUpload);
            newFile.Url = System.IO.Path.GetFileName(_fileToUpload);
            newFile.Overwrite = true;


            SPInfo _spInfo = new SPInfo(_uri);
            List list = _spInfo.site.Lists.GetById(_destination.ListId);
            _spInfo.clientContext.Load(list);
            _spInfo.clientContext.ExecuteQuery();

            if (_destination.IsList)
            {
                try
                {
                    SP.File fileupload = list.RootFolder.Files.Add(newFile);
                    _spInfo.clientContext.Load(fileupload);
                    _spInfo.clientContext.ExecuteQuery();
                }
                catch
                {
                    return false;
                }
            }
            else
            {
                CamlQuery query = new CamlQuery();

                query.ViewXml = "<View Scope='RecursiveAll'>" +
                                "   <Query> " +
                                "   <Where> " +
                                "       <Eq>" +
                                "           <FieldRef Name='FileRef' />" +
                                "           <Value Type='Text'>" + _destination.FileRef + "</Value>" +
                                "       </Eq>" +
                                "      </And>" +
                                "   </Where> " +
                                "   </Query> " +
                                "</View>";

                ListItemCollection itemcollection = list.GetItems(query);

                _spInfo.clientContext.Load(itemcollection);
                _spInfo.clientContext.ExecuteQuery();

                if (itemcollection.Count > 1 || itemcollection.Count == 0)
                    return false;

                ListItem item = itemcollection[0];
                if (item.FileSystemObjectType == FileSystemObjectType.Folder)
                {
                    try
                    {
                        Folder folder = item.ParentList.ParentWeb.GetFolderByServerRelativeUrl(item.FieldValues["FileRef"].ToString());
                        _spInfo.clientContext.Load(folder);
                        _spInfo.clientContext.ExecuteQuery();

                        SP.File fileupload = folder.Files.Add(newFile);
                        _spInfo.clientContext.Load(fileupload);
                        _spInfo.clientContext.ExecuteQuery();
                    }
                    catch
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        #endregion

        #region Service procs

        // проверка на наличие шаблона
        Boolean checkIsLibrary(ContentTypeCollection _ctc)
        {
            this.clientContext.Load(_ctc);
            this.clientContext.ExecuteQuery();

            foreach (ContentType ct in _ctc)
            {
                if (ct.DocumentTemplateUrl != String.Empty)
                {
                    return true;
                }
            }
            return false;
        }

        #endregion


    }
}

